home *** CD-ROM | disk | FTP | other *** search
/ GameStar 2004 April / Gamestar_61_2004-04_dvdb.iso / DVDStar / Editace / hltp.exe / {app} / Source Code / Zoners Half-Life Tools / common / threads.cpp < prev    next >
C/C++ Source or Header  |  2002-11-15  |  15KB  |  682 lines

  1. #ifdef SYSTEM_WIN32
  2. #define WIN32_LEAN_AND_MEAN
  3. #include <windows.h>
  4. #include <malloc.h>
  5. #endif
  6.  
  7. #ifdef HAVE_CONFIG_H
  8. #include "config.h"
  9. #endif
  10.  
  11. #include "cmdlib.h"
  12. #include "messages.h"
  13. #include "log.h"
  14. #include "threads.h"
  15. #include "blockmem.h"
  16.  
  17. #ifdef SYSTEM_POSIX
  18. #ifdef HAVE_SYS_TIME_H
  19. #include <sys/time.h>
  20. #endif
  21. #ifdef HAVE_SYS_RESOURCE_H
  22. #include <sys/resource.h>
  23. #include <pthread.h>
  24. #endif
  25. #ifdef HAVE_PTHREAD_H
  26. #include <pthread.h>
  27. #endif
  28. #endif
  29.  
  30. #include "hlassert.h"
  31.  
  32. q_threadpriority g_threadpriority = DEFAULT_THREAD_PRIORITY;
  33.  
  34. #define THREADTIMES_SIZE 100
  35. #define THREADTIMES_SIZEf (float)(THREADTIMES_SIZE)
  36.  
  37. static int      dispatch = 0;
  38. static int      workcount = 0;
  39. static int      oldf = 0;
  40. static bool     pacifier = false;
  41. static bool     threaded = false;
  42. static double   threadstart = 0;
  43. static double   threadtimes[THREADTIMES_SIZE];
  44.  
  45. int             GetThreadWork()
  46. {
  47.     int             r, f, i;
  48.     double          ct, finish, finish2, finish3;
  49.  
  50.     ThreadLock();
  51.  
  52.     if (dispatch == 0)
  53.     {
  54.         oldf = 0;
  55.     }
  56.  
  57.     if (dispatch > workcount)
  58.     {
  59.         Developer(DEVELOPER_LEVEL_ERROR, "dispatch > workcount!!!\n");
  60.         ThreadUnlock();
  61.         return -1;
  62.     }
  63.     if (dispatch == workcount)
  64.     {
  65.         Developer(DEVELOPER_LEVEL_MESSAGE, "dispatch == workcount, work is complete\n");
  66.         ThreadUnlock();
  67.         return -1;
  68.     }
  69.     if (dispatch < 0)
  70.     {
  71.         Developer(DEVELOPER_LEVEL_ERROR, "negative dispatch!!!\n");
  72.         ThreadUnlock();
  73.         return -1;
  74.     }
  75.  
  76.     f = THREADTIMES_SIZE * dispatch / workcount;
  77.     if (pacifier)
  78.     {
  79.         printf("\r%6d /%6d", dispatch, workcount);
  80. #ifdef ZHLT_PROGRESSFILE // AJM
  81.         if (g_progressfile)
  82.         {
  83.             
  84.  
  85.         }
  86. #endif
  87.  
  88.         if (f != oldf)
  89.         {
  90.             ct = I_FloatTime();
  91.             /* Fill in current time for threadtimes record */
  92.             for (i = oldf; i <= f; i++)
  93.             {
  94.                 if (threadtimes[i] < 1)
  95.                 {
  96.                     threadtimes[i] = ct;
  97.                 }
  98.             }
  99.             oldf = f;
  100.  
  101.             if (f > 10)
  102.             {
  103.                 finish = (ct - threadtimes[0]) * (THREADTIMES_SIZEf - f) / f;
  104.                 finish2 = 10.0 * (ct - threadtimes[f - 10]) * (THREADTIMES_SIZEf - f) / THREADTIMES_SIZEf;
  105.                 finish3 = THREADTIMES_SIZEf * (ct - threadtimes[f - 1]) * (THREADTIMES_SIZEf - f) / THREADTIMES_SIZEf;
  106.  
  107.                 if (finish > 1.0)
  108.                 {
  109.                     printf("  (%d%%: est. time to completion %ld/%ld/%ld secs)   ", f, (long)(finish), (long)(finish2),
  110.                            (long)(finish3));
  111. #ifdef ZHLT_PROGRESSFILE // AJM
  112.                     if (g_progressfile)
  113.                     {
  114.  
  115.  
  116.                     }
  117. #endif
  118.                 }
  119.                 else
  120.                 {
  121.                     printf("  (%d%%: est. time to completion <1 sec)   ", f);
  122.  
  123. #ifdef ZHLT_PROGRESSFILE // AJM
  124.                     if (g_progressfile)
  125.                     {
  126.  
  127.  
  128.                     }
  129. #endif
  130.                 }
  131.             }
  132.         }
  133.     }
  134.     else
  135.     {
  136.         if (f != oldf)
  137.         {
  138.             oldf = f;
  139.             switch (f)
  140.             {
  141.             case 10:
  142.             case 20:
  143.             case 30:
  144.             case 40:
  145.             case 50:
  146.             case 60:
  147.             case 70:
  148.             case 80:
  149.             case 90:
  150.             case 100:
  151. /*
  152.             case 5:
  153.             case 15:
  154.             case 25:
  155.             case 35:
  156.             case 45:
  157.             case 55:
  158.             case 65:
  159.             case 75:
  160.             case 85:
  161.             case 95:
  162. */
  163.                 printf("%d%%...", f);
  164.             default:
  165.                 break;
  166.             }
  167.         }
  168.     }
  169.  
  170.     r = dispatch;
  171.     dispatch++;
  172.  
  173.     ThreadUnlock();
  174.     return r;
  175. }
  176.  
  177. q_threadfunction workfunction;
  178.  
  179. #ifdef SYSTEM_WIN32
  180. #pragma warning(push)
  181. #pragma warning(disable: 4100)                             // unreferenced formal parameter
  182. #endif
  183. static void     ThreadWorkerFunction(int unused)
  184. {
  185.     int             work;
  186.  
  187.     while ((work = GetThreadWork()) != -1)
  188.     {
  189.         workfunction(work);
  190.     }
  191. }
  192.  
  193. #ifdef SYSTEM_WIN32
  194. #pragma warning(pop)
  195. #endif
  196.  
  197. void            RunThreadsOnIndividual(int workcnt, bool showpacifier, q_threadfunction func)
  198. {
  199.     workfunction = func;
  200.     RunThreadsOn(workcnt, showpacifier, ThreadWorkerFunction);
  201. }
  202.  
  203. #ifndef SINGLE_THREADED
  204.  
  205. /*====================
  206. | Begin SYSTEM_WIN32
  207. =*/
  208. #ifdef SYSTEM_WIN32
  209.  
  210. #define    USED
  211. #include <windows.h>
  212.  
  213. int             g_numthreads = DEFAULT_NUMTHREADS;
  214. static CRITICAL_SECTION crit;
  215. static int      enter;
  216.  
  217. void            ThreadSetPriority(q_threadpriority type)
  218. {
  219.     int             val;
  220.  
  221.     g_threadpriority = type;
  222.  
  223.     switch (g_threadpriority)
  224.     {
  225.     case eThreadPriorityLow:
  226.         val = IDLE_PRIORITY_CLASS;
  227.         break;
  228.  
  229.     case eThreadPriorityHigh:
  230.         val = HIGH_PRIORITY_CLASS;
  231.         break;
  232.  
  233.     case eThreadPriorityNormal:
  234.     default:
  235.         val = NORMAL_PRIORITY_CLASS;
  236.         break;
  237.     }
  238.  
  239.     SetPriorityClass(GetCurrentProcess(), val);
  240. }
  241.  
  242. #if 0
  243. static void     AdjustPriority(HANDLE hThread)
  244. {
  245.     int             val;
  246.  
  247.     switch (g_threadpriority)
  248.     {
  249.     case eThreadPriorityLow:
  250.         val = THREAD_PRIORITY_HIGHEST;
  251.         break;
  252.  
  253.     case eThreadPriorityHigh:
  254.         val = THREAD_PRIORITY_LOWEST;
  255.         break;
  256.  
  257.     case eThreadPriorityNormal:
  258.     default:
  259.         val = THREAD_PRIORITY_NORMAL;
  260.         break;
  261.     }
  262.     SetThreadPriority(hThread, val);
  263. }
  264. #endif
  265.  
  266. void            ThreadSetDefault()
  267. {
  268.     SYSTEM_INFO     info;
  269.  
  270.     if (g_numthreads == -1)                                // not set manually
  271.     {
  272.         GetSystemInfo(&info);
  273.         g_numthreads = info.dwNumberOfProcessors;
  274.         if (g_numthreads < 1 || g_numthreads > 32)
  275.         {
  276.             g_numthreads = 1;
  277.         }
  278.     }
  279. }
  280.  
  281. void            ThreadLock()
  282. {
  283.     if (!threaded)
  284.     {
  285.         return;
  286.     }
  287.     EnterCriticalSection(&crit);
  288.     if (enter)
  289.     {
  290.         Warning("Recursive ThreadLock\n");
  291.     }
  292.     enter++;
  293. }
  294.  
  295. void            ThreadUnlock()
  296. {
  297.     if (!threaded)
  298.     {
  299.         return;
  300.     }
  301.     if (!enter)
  302.     {
  303.         Error("ThreadUnlock without lock\n");
  304.     }
  305.     enter--;
  306.     LeaveCriticalSection(&crit);
  307. }
  308.  
  309. q_threadfunction q_entry;
  310.  
  311. static DWORD WINAPI ThreadEntryStub(LPVOID pParam)
  312. {
  313.     q_entry((int)pParam);
  314.     return 0;
  315. }
  316.  
  317. void            threads_InitCrit()
  318. {
  319.     InitializeCriticalSection(&crit);
  320.     threaded = true;
  321. }
  322.  
  323. void            threads_UninitCrit()
  324. {
  325.     DeleteCriticalSection(&crit);
  326. }
  327.  
  328. void            RunThreadsOn(int workcnt, bool showpacifier, q_threadfunction func)
  329. {
  330.     DWORD           threadid[MAX_THREADS];
  331.     HANDLE          threadhandle[MAX_THREADS];
  332.     int             i;
  333.     double          start, end;
  334.  
  335.     threadstart = I_FloatTime();
  336.     start = threadstart;
  337.     for (i = 0; i < THREADTIMES_SIZE; i++)
  338.     {
  339.         threadtimes[i] = 0;
  340.     }
  341.     dispatch = 0;
  342.     workcount = workcnt;
  343.     oldf = -1;
  344.     pacifier = showpacifier;
  345.     threaded = true;
  346.     q_entry = func;
  347.  
  348.     if (workcount < dispatch)
  349.     {
  350.         Developer(DEVELOPER_LEVEL_ERROR, "RunThreadsOn: Workcount(%i) < dispatch(%i)\n", workcount, dispatch);
  351.     }
  352.     hlassume(workcount >= dispatch, assume_BadWorkcount);
  353.  
  354.     //
  355.     // Create all the threads (suspended)
  356.     //
  357.     threads_InitCrit();
  358.     for (i = 0; i < g_numthreads; i++)
  359.     {
  360.         HANDLE          hThread = CreateThread(NULL,
  361.                                                0,
  362.                                                (LPTHREAD_START_ROUTINE) ThreadEntryStub,
  363.                                                (LPVOID) i,
  364.                                                CREATE_SUSPENDED,
  365.                                                &threadid[i]);
  366.  
  367.         if (hThread != NULL)
  368.         {
  369.             threadhandle[i] = hThread;
  370.         }
  371.         else
  372.         {
  373.             LPVOID          lpMsgBuf;
  374.  
  375.             FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  376.                           FORMAT_MESSAGE_FROM_SYSTEM |
  377.                           FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),       // Default language
  378.                           (LPTSTR) & lpMsgBuf, 0, NULL);
  379.             // Process any inserts in lpMsgBuf.
  380.             // ...
  381.             // Display the string.
  382.             Developer(DEVELOPER_LEVEL_ERROR, "CreateThread #%d [%08X] failed : %s\n", i, threadhandle[i], lpMsgBuf);
  383.             Fatal(assume_THREAD_ERROR, "Unable to create thread #%d", i);
  384.             // Free the buffer.
  385.             LocalFree(lpMsgBuf);
  386.         }
  387.     }
  388.     CheckFatal();
  389.  
  390.     // Start all the threads
  391.     for (i = 0; i < g_numthreads; i++)
  392.     {
  393.         if (ResumeThread(threadhandle[i]) == 0xFFFFFFFF)
  394.         {
  395.             LPVOID          lpMsgBuf;
  396.  
  397.             FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  398.                           FORMAT_MESSAGE_FROM_SYSTEM |
  399.                           FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),       // Default language
  400.                           (LPTSTR) & lpMsgBuf, 0, NULL);
  401.             // Process any inserts in lpMsgBuf.
  402.             // ...
  403.             // Display the string.
  404.             Developer(DEVELOPER_LEVEL_ERROR, "ResumeThread #%d [%08X] failed : %s\n", i, threadhandle[i], lpMsgBuf);
  405.             Fatal(assume_THREAD_ERROR, "Unable to start thread #%d", i);
  406.             // Free the buffer.
  407.             LocalFree(lpMsgBuf);
  408.         }
  409.     }
  410.     CheckFatal();
  411.  
  412.     // Wait for threads to complete
  413.     for (i = 0; i < g_numthreads; i++)
  414.     {
  415.         Developer(DEVELOPER_LEVEL_MESSAGE, "WaitForSingleObject on thread #%d [%08X]\n", i, threadhandle[i]);
  416.         WaitForSingleObject(threadhandle[i], INFINITE);
  417.     }
  418.     threads_UninitCrit();
  419.  
  420.     q_entry = NULL;
  421.     threaded = false;
  422.     end = I_FloatTime();
  423.     if (pacifier)
  424.     {
  425.         printf("\r%60s\r", "");
  426.     }
  427.     Log(" (%.2f seconds)\n", end - start);
  428. }
  429.  
  430. #endif
  431.  
  432. /*=
  433. | End SYSTEM_WIN32
  434. =====================*/
  435.  
  436. /*====================
  437. | Begin SYSTEM_POSIX
  438. =*/
  439. #ifdef SYSTEM_POSIX
  440.  
  441. #define    USED
  442.  
  443. int             g_numthreads = DEFAULT_NUMTHREADS;
  444.  
  445. void            ThreadSetPriority(q_threadpriority type)
  446. {
  447.     int             val;
  448.  
  449.     g_threadpriority = type;
  450.  
  451.     // Currently in Linux land users are incapable of raising the priority level of their processes
  452.     // Unless you are root -high is useless . . . 
  453.     switch (g_threadpriority)
  454.     {
  455.     case eThreadPriorityLow:
  456.         val = PRIO_MAX;
  457.         break;
  458.  
  459.     case eThreadPriorityHigh:
  460.         val = PRIO_MIN;
  461.         break;
  462.  
  463.     case eThreadPriorityNormal:
  464.     default:
  465.         val = 0;
  466.         break;
  467.     }
  468.     setpriority(PRIO_PROCESS, 0, val);
  469. }
  470.  
  471. void            ThreadSetDefault()
  472. {
  473.     if (g_numthreads == -1)
  474.     {
  475.         g_numthreads = 1;
  476.     }
  477. }
  478.  
  479. typedef void*    pthread_addr_t;
  480. pthread_mutex_t* my_mutex;
  481.  
  482. void            ThreadLock()
  483. {
  484.     if (my_mutex)
  485.     {
  486.         pthread_mutex_lock(my_mutex);
  487.     }
  488. }
  489.  
  490. void            ThreadUnlock()
  491. {
  492.     if (my_mutex)
  493.     {
  494.         pthread_mutex_unlock(my_mutex);
  495.     }
  496. }
  497.  
  498. q_threadfunction q_entry;
  499.  
  500. static void*    CDECL ThreadEntryStub(void* pParam)
  501. {
  502.     q_entry((int)pParam);
  503.     return NULL;
  504. }
  505.  
  506. void            threads_InitCrit()
  507. {
  508.     pthread_mutexattr_t mattrib;
  509.  
  510.     if (!my_mutex)
  511.     {
  512.         my_mutex = (pthread_mutex_t*)Alloc(sizeof(*my_mutex));
  513.         if (pthread_mutexattr_init(&mattrib) == -1)
  514.         {
  515.             Error("pthread_mutex_attr_init failed");
  516.         }
  517.         if (pthread_mutex_init(my_mutex, &mattrib) == -1)
  518.         {
  519.             Error("pthread_mutex_init failed");
  520.         }
  521.     }
  522. }
  523.  
  524. void            threads_UninitCrit()
  525. {
  526.     Free(my_mutex);
  527.     my_mutex = NULL;
  528. }
  529.  
  530. /*
  531.  * =============
  532.  * RunThreadsOn
  533.  * =============
  534.  */
  535. void            RunThreadsOn(int workcnt, bool showpacifier, q_threadfunction func)
  536. {
  537.     int             i;
  538.     pthread_t       work_threads[MAX_THREADS];
  539.     pthread_addr_t  status;
  540.     pthread_attr_t  attrib;
  541.     double          start, end;
  542.  
  543.     threadstart = I_FloatTime();
  544.     start = threadstart;
  545.     for (i = 0; i < THREADTIMES_SIZE; i++)
  546.     {
  547.         threadtimes[i] = 0;
  548.     }
  549.  
  550.     dispatch = 0;
  551.     workcount = workcnt;
  552.     oldf = -1;
  553.     pacifier = showpacifier;
  554.     threaded = true;
  555.     q_entry = func;
  556.  
  557.     if (pacifier)
  558.     {
  559.         setbuf(stdout, NULL);
  560.     }
  561.  
  562.     threads_InitCrit();
  563.  
  564.     if (pthread_attr_init(&attrib) == -1)
  565.     {
  566.         Error("pthread_attr_init failed");
  567.     }
  568. #ifdef _POSIX_THREAD_ATTR_STACKSIZE
  569.     if (pthread_attr_setstacksize(&attrib, 0x400000) == -1)
  570.     {
  571.         Error("pthread_attr_setstacksize failed");
  572.     }
  573. #endif
  574.  
  575.     for (i = 0; i < g_numthreads; i++)
  576.     {
  577.         if (pthread_create(&work_threads[i], &attrib, ThreadEntryStub, (void*)i) == -1)
  578.         {
  579.             Error("pthread_create failed");
  580.         }
  581.     }
  582.  
  583.     for (i = 0; i < g_numthreads; i++)
  584.     {
  585.         if (pthread_join(work_threads[i], &status) == -1)
  586.         {
  587.             Error("pthread_join failed");
  588.         }
  589.     }
  590.  
  591.     threads_UninitCrit();
  592.  
  593.     q_entry = NULL;
  594.     threaded = false;
  595.  
  596.     end = I_FloatTime();
  597.     if (pacifier)
  598.     {
  599.         printf("\r%60s\r", "");
  600.     }
  601.  
  602.     Log(" (%.2f seconds)\n", end - start);
  603. }
  604.  
  605. #endif /*SYSTEM_POSIX */
  606.  
  607. /*=
  608. | End SYSTEM_POSIX
  609. =====================*/
  610.  
  611. #endif /*SINGLE_THREADED */
  612.  
  613. /*====================
  614. | Begin SINGLE_THREADED
  615. =*/
  616. #ifdef SINGLE_THREADED
  617.  
  618. int             g_numthreads = 1;
  619.  
  620. void            ThreadSetPriority(q_threadpriority type)
  621. {
  622. }
  623.  
  624. void            threads_InitCrit()
  625. {
  626. }
  627.  
  628. void            threads_UninitCrit()
  629. {
  630. }
  631.  
  632. void            ThreadSetDefault()
  633. {
  634.     g_numthreads = 1;
  635. }
  636.  
  637. void            ThreadLock()
  638. {
  639. }
  640.  
  641. void            ThreadUnlock()
  642. {
  643. }
  644.  
  645. void            RunThreadsOn(int workcnt, bool showpacifier, q_threadfunction func)
  646. {
  647.     int             i;
  648.     double          start, end;
  649.  
  650.     dispatch = 0;
  651.     workcount = workcnt;
  652.     oldf = -1;
  653.     pacifier = showpacifier;
  654.     threadstart = I_FloatTime();
  655.     start = threadstart;
  656.     for (i = 0; i < THREADTIMES_SIZE; i++)
  657.     {
  658.         threadtimes[i] = 0.0;
  659.     }
  660.  
  661.     if (pacifier)
  662.     {
  663.         setbuf(stdout, NULL);
  664.     }
  665.     func(0);
  666.  
  667.     end = I_FloatTime();
  668.  
  669.     if (pacifier)
  670.     {
  671.         printf("\r%60s\r", "");
  672.     }
  673.  
  674.     Log(" (%.2f seconds)\n", end - start);
  675. }
  676.  
  677. #endif
  678.  
  679. /*=
  680. | End SINGLE_THREADED
  681. =====================*/
  682.